A device driver is software that controls a hardware component or peripheral device of a computer, such as a printer. A device driver is responsible for accessing the hardware registers of the device and often includes an interrupt handler to service interrupts generated by the device or an application executing on the computer. Conventionally, a device driver was linked to the operating system (O.S.) kernel when the kernel was built. However, recent operating systems have dynamically loadable/linkable device drivers that are installed from files after the operating system is running. For example, in the Windows.RTM. 95/98 operating systems provided by Microsoft Corp., dynamically loadable/linkable drivers (files or code) are identified with a .DRV extension in the file name, and dynamically loadable libraries are identified with a .DLL extension. More recently, dynamically loadable code in general, whether it be a "driver" or a "library", is identified simply with a .DLL extension. Such operating systems, drivers, and/or libraries provide flexibility for overall memory management operations and computing performance efficiency considerations. For purposes of this discussion, a dynamically loadable/linkable driver, library and/or other code having data and/or executable instructions will simply be referred to herein as a DLL file. Additionally, the terms "load" and "link" will be referred to jointly herein simply as "load". Moreover, the discussion will occur in the context of a printer driver, although other drivers and/or dynamically loadable/linkable files are equally applicable.
Typically, the operating system "loads" a DLL file when an application or other executing process requests to use it. An application is a self-contained program that performs a specific function or duty, typically for the user. Examples include a word processor, graphic design package, electronic mail program, etc. Generally, the O.S. loads the DLL file by: (i) copying the DLL file from an external storage medium, such as a disk drive, into random access memory (RAM) for execution if it is not already resident in RAM, (ii) setting and/or incrementing an internal reference count for that DLL file, (iii) initializing the DLL file, and (iv) linking the application/process with the DLL file (or in other words, establishing communication between the application and the DLL file) so that the application can execute any one of a collection of functions residing in the DLL file. The internal reference count allows the O.S. to track how many applications or processes are currently using the DLL file. This enables the O.S. to determine whether or not the DLL file is already resident in memory and to bring it into memory (RAM) only if it is not already resident. For example, if the DLL file is not already resident in memory (i.e., the reference count is zero), then a "load" of the DLL file includes placing it in memory (i.e., copied from disk) for execution and setting/incrementing the reference count. On the other hand, if the DLL file is already resident in memory when an application needs to use it (i.e., the reference count is a non-zero value), then a "load" simply includes incrementing the reference count to reflect another use of the DLL file.
Additionally, the reference count enables the O.S. to determine when to unload the DLL file. Generally, the O.S. unloads the DLL file by (i) decrementing the internal reference count for that DLL file, (ii) de-initializing the DLL file, and (iii) unlinking the application/process from the DLL file (or in other words, breaking communication between the application and the DLL file) and removing the DLL file out of RAM (i.e., marking its memory space as unused). For example, if no other application is currently using the DLL file (i.e., if the reference count will go to zero) when an application completes its use of the DLL file, then an "unload" includes decrementing the reference count and removing the DLL file from memory (marking its memory space as "unused"). If another application/process is currently using the DLL file (i.e., the reference count will not go to zero), then an "unload" simply includes decrementing the reference count, and the DLL file is kept resident in memory for continued use by the other application(s).
The loading and unloading of a DLL file can occur multiple times over a very short period of time. For example, when an application is initially launched (executed), a printer driver DLL file is loaded and unloaded multiple times by the O.S. for the application to initially establish communication with the printer device. An application initiates communication with a DLL file by creating (requesting via the O.S.) a device context for that device DLL file. This is commonly referred to as a "CreateDC()" command in a Windows 95/98 environment and is the mechanism that enables the O.S. to establish the communication structure and parameters between the application and the driver DLL file. To this regard, in a printer driver context, a CreateDC() or similar command typically executes a series of "query" functions including, for example, the O.S. loading the printer driver to determine what the driver version number is (i.e., executing a driver version detect function in the DLL file), and then unloading the driver; loading the printer driver to inquire what the resolution capability of the printer is (i.e., executing a resolution detect function in the DLL file), and then unloading the driver; loading the printer driver to inquire what paper size the printer supports (i.e., executing a paper size detect function in the DLL file), and then unloading the driver; loading the printer driver to inquire what the paper orientation is (i.e., executing an orientation detect function in the DLL file), and then unloading the driver; and so forth for other printer features also. Finally, after this series of loading/unloading occurs to query the printer driver, an "enabling" function is executed in the DLL file to enable or create the device context for the driver for further use by the application.
As indicated, the sequence of the above noted load/unload functions may be performed by the O.S. for each CreateDC() command executed by the application. Other functions provided by the DLL file may also be called by the application once the device context is established. In any case, after the application has completed its calls to the DLL file subsequent to a CreateDC() command, the application executes a DeleteDC() command to break the communication link between the application and the DLL file. In other words, the O.S. "unloads" the driver. Note also that an application may execute CreateDC() and DeleteDC() commands multiple times in its program code, depending on design criteria, desired execution efficiency, memory considerations, and other factors.
Although one idea behind unloading a DLL file is to free up memory resources, a potential effect of multiple instances of loading and unloading a DLL file in a short period of time is to undesirably tax a system's processor and memory resources because of the intensive file and memory management activities that occur. Additionally, the initialization and de-initialization of the DLL file each time it is loaded into memory and subsequently unloaded causes a lot of code to be processed repeatedly which can be perceived as a performance problem. Notably, this performance penalty becomes more severe the larger the DLL file becomes and the more complex the initialization and de-initialization code becomes (as drivers become more and more sophisticated). Disadvantageously, these events can result in undesirable processing delays that may even be noticed by a user.
Accordingly, an object of the present invention is to provide a tool and method for managing dynamically loadable/linkable files.